/**
 * 可配置的枚举分析工具
 * 通过配置文件控制分析范围和行为
 */

const fs = require('fs');
const Papa = require('papaparse');
const path = require('path');

// 读取配置文件
function loadConfig() {
    try {
        const configPath = '枚举分析配置.json';
        const configData = fs.readFileSync(configPath, 'utf-8');
        const config = JSON.parse(configData);
        return config;
    } catch (e) {
        console.error('❌ 读取配置文件失败:', e.message);
        console.log('使用默认配置...\n');
        return getDefaultConfig();
    }
}

// 默认配置
function getDefaultConfig() {
    return {
        "分析范围": {
            "测试模式": true,
            "测试行数": 10000
        },
        "文件选择": {
            "分析所有文件": false,
            "指定文件": ["output/基本设施.csv"]
        },
        "字段识别": {
            "唯一性阈值": 0.5,
            "ID关键词": ["id", "_id", "编号", "序号", "uuid", "guid"]
        },
        "关系分析": {
            "启用": true,
            "最小关系强度": 1.5
        },
        "输出设置": {
            "输出目录": "output",
            "报告文件名格式": "{文件名}_枚举分析.html"
        }
    };
}

// 判断是否为唯一性字段
function isUniqueField(columnName, uniqueCount, totalCount, config) {
    const lowerName = columnName.toLowerCase();
    const idKeywords = config.字段识别.ID关键词;
    
    // 方法1: 关键词匹配
    const nameMatch = idKeywords.some(keyword => lowerName.includes(keyword));
    
    // 方法2: 唯一值比例
    const uniqueRatio = uniqueCount / totalCount;
    const ratioMatch = uniqueRatio > config.字段识别.唯一性阈值;
    
    return nameMatch || ratioMatch;
}

// 收集字段统计
function collectStats(filePath, config) {
    return new Promise((resolve, reject) => {
        const testMode = config.分析范围.测试模式;
        const maxRows = testMode ? config.分析范围.测试行数 : Infinity;
        
        console.log(`\n📊 扫描: ${path.basename(filePath)}`);
        if (testMode) {
            console.log(`   模式: 测试 (前${maxRows}行)`);
        } else {
            console.log(`   模式: 完整分析`);
        }
        
        const fieldStats = {};
        let totalRows = 0;
        let columns = [];
        
        const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });

        Papa.parse(stream, {
            header: true,
            skipEmptyLines: true,
            
            step: function(result, parser) {
                totalRows++;

                if (totalRows === 1 && result.meta.fields) {
                    columns = result.meta.fields;
                    columns.forEach(col => {
                        fieldStats[col] = {
                            values: new Set(),
                            total: 0
                        };
                    });
                }

                columns.forEach(col => {
                    const value = result.data[col];
                    if (!fieldStats[col]) return;
                    
                    fieldStats[col].total++;
                    if (value && value !== '数据不存在') {
                        fieldStats[col].values.add(value);
                    }
                });

                if (totalRows >= maxRows) {
                    parser.abort();
                }

                if (totalRows % 100000 === 0) {
                    process.stdout.write(`\r   进度: ${totalRows.toLocaleString()} 行`);
                }
            },

            complete: function() {
                if (totalRows >= 100000) {
                    console.log(''); // 换行
                }
                console.log(`   ✅ 完成: ${totalRows.toLocaleString()} 行\n`);
                
                // 转换统计数据
                Object.keys(fieldStats).forEach(col => {
                    fieldStats[col].uniqueCount = fieldStats[col].values.size;
                    fieldStats[col].uniqueRatio = fieldStats[col].uniqueCount / totalRows;
                    fieldStats[col].values = Array.from(fieldStats[col].values);
                });
                
                resolve({ totalRows, columns, fieldStats });
            },

            error: reject
        });
    });
}

// 发现字段关系
function discoverRelationships(filePath, stats, config) {
    if (!config.关系分析.启用) {
        console.log('⏭️  关系分析已禁用\n');
        return Promise.resolve([]);
    }
    
    return new Promise((resolve) => {
        console.log(`🔍 分析字段关系...`);
        
        const { columns, fieldStats } = stats;
        const testMode = config.分析范围.测试模式;
        const maxRows = testMode ? config.分析范围.测试行数 : Infinity;
        
        // 筛选可分析字段
        const analyzableFields = columns.filter(col => {
            const stat = fieldStats[col];
            return !isUniqueField(col, stat.uniqueCount, stat.total, config);
        });
        
        if (analyzableFields.length < 2) {
            console.log('   可分析字段不足，跳过关系分析\n');
            return resolve([]);
        }
        
        console.log(`   可分析字段: ${analyzableFields.join(', ')}`);
        
        // 生成所有可能的字段对
        const pairs = [];
        for (let i = 0; i < analyzableFields.length - 1; i++) {
            for (let j = i + 1; j < analyzableFields.length; j++) {
                pairs.push([analyzableFields[i], analyzableFields[j]]);
            }
        }
        
        console.log(`   尝试 ${pairs.length} 个字段组合...\n`);
        
        // 分析每对字段
        const promises = pairs.map(([field1, field2]) => 
            analyzeFieldPair(filePath, field1, field2, maxRows, config)
        );
        
        Promise.all(promises).then(results => {
            const validRelationships = results.filter(r => r !== null);
            resolve(validRelationships);
        });
    });
}

// 分析字段对
function analyzeFieldPair(filePath, field1, field2, maxRows, config) {
    return new Promise((resolve) => {
        const relationMap1to2 = new Map();
        const relationMap2to1 = new Map();
        let rowCount = 0;
        
        const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
        
        Papa.parse(stream, {
            header: true,
            skipEmptyLines: true,
            step: function(result, parser) {
                rowCount++;
                
                const value1 = result.data[field1];
                const value2 = result.data[field2];
                
                if (value1 && value2 && 
                    value1 !== '数据不存在' && 
                    value2 !== '数据不存在') {
                    
                    if (!relationMap1to2.has(value1)) {
                        relationMap1to2.set(value1, new Set());
                    }
                    relationMap1to2.get(value1).add(value2);
                    
                    if (!relationMap2to1.has(value2)) {
                        relationMap2to1.set(value2, new Set());
                    }
                    relationMap2to1.get(value2).add(value1);
                }
                
                if (rowCount >= maxRows) {
                    parser.abort();
                }
            },
            complete: function() {
                const minStrength = config.关系分析.最小关系强度;
                
                const analysis1to2 = analyzeRelation(field1, field2, relationMap1to2, minStrength);
                const analysis2to1 = analyzeRelation(field2, field1, relationMap2to1, minStrength);
                
                let bestRelation = null;
                if (analysis1to2 && analysis2to1) {
                    bestRelation = analysis1to2.strength > analysis2to1.strength ? analysis1to2 : analysis2to1;
                } else {
                    bestRelation = analysis1to2 || analysis2to1;
                }
                
                if (bestRelation) {
                    console.log(`   ✅ ${bestRelation.parent} → ${bestRelation.child} (强度: ${bestRelation.strength.toFixed(2)})`);
                }
                
                resolve(bestRelation);
            }
        });
    });
}

// 分析关系
function analyzeRelation(parentField, childField, relationMap, minStrength) {
    const parentCount = relationMap.size;
    let totalChildVariety = 0;
    const mappings = {};
    
    relationMap.forEach((childSet, parentValue) => {
        totalChildVariety += childSet.size;
        mappings[parentValue] = Array.from(childSet).sort();
    });
    
    const avgChildPerParent = totalChildVariety / parentCount;
    
    // 判断有效性
    const isValid = avgChildPerParent >= minStrength && parentCount < totalChildVariety;
    
    if (!isValid) return null;
    
    return {
        parent: parentField,
        child: childField,
        parentCount,
        avgChildPerParent: avgChildPerParent.toFixed(2),
        strength: avgChildPerParent,
        mappings
    };
}

// 生成HTML报告
function generateReport(stats, relationships, config, sourceFile, outputPath) {
    const { totalRows, columns, fieldStats } = stats;
    
    // 分类字段
    const analyzableFields = [];
    const skippedFields = [];
    
    columns.forEach(col => {
        const stat = fieldStats[col];
        if (isUniqueField(col, stat.uniqueCount, stat.total, config)) {
            skippedFields.push({
                name: col,
                uniqueCount: stat.uniqueCount,
                ratio: (stat.uniqueRatio * 100).toFixed(1)
            });
        } else {
            analyzableFields.push(col);
        }
    });
    
    // 生成字段表格
    let fieldTablesHtml = '';
    analyzableFields.forEach(col => {
        const stat = fieldStats[col];
        fieldTablesHtml += `
            <div class="field-box">
                <h3>${col}</h3>
                <div class="meta">
                    枚举类型数: <strong>${stat.uniqueCount}</strong> | 
                    总记录: ${stat.total.toLocaleString()} | 
                    覆盖率: ${((stat.total - stat.values.filter(v => !v).length) / stat.total * 100).toFixed(1)}%
                </div>
                <div class="value-list">
                    ${stat.values.slice(0, 50).map((value, idx) => 
                        `<span class="value-tag">${idx + 1}. ${value}</span>`
                    ).join('')}
                    ${stat.values.length > 50 ? 
                        `<span class="more-tag">... 还有 ${stat.values.length - 50} 个</span>` 
                        : ''}
                </div>
            </div>
        `;
    });
    
    // 生成关系分析
    let relationHtml = '';
    if (relationships.length > 0) {
        relationships.forEach(rel => {
            const sortedMappings = Object.entries(rel.mappings)
                .sort((a, b) => b[1].length - a[1].length);
            
            relationHtml += `
                <div class="relation-box">
                    <h3>${rel.parent} → ${rel.child}</h3>
                    <div class="meta">
                        ${rel.parent}有 <strong>${rel.parentCount}</strong> 种 | 
                        平均每个包含 <strong>${rel.avgChildPerParent}</strong> 个${rel.child}
                    </div>
                    <div class="relation-list">
                        ${sortedMappings.map(([parent, children]) => `
                            <div class="relation-item">
                                <div class="parent">${parent} <span class="badge">${children.length}</span></div>
                                <div class="children">
                                    ${children.map(c => `<span class="tag">${c}</span>`).join('')}
                                </div>
                            </div>
                        `).join('')}
                    </div>
                </div>
            `;
        });
    } else {
        relationHtml = '<p style="color:#999;text-align:center;padding:30px">未发现符合条件的字段关系</p>';
    }
    
    const html = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>枚举分析 - ${path.basename(sourceFile)}</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: "Microsoft YaHei", Arial, sans-serif; background: #f5f5f5; padding: 20px; line-height: 1.6; }
        .container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 5px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
        .header { background: #2c3e50; color: white; padding: 20px 30px; border-radius: 5px 5px 0 0; }
        .header h1 { font-size: 1.6em; margin-bottom: 5px; }
        .header .info { opacity: 0.9; font-size: 0.9em; }
        .summary { display: flex; padding: 15px 30px; background: #ecf0f1; border-bottom: 1px solid #ddd; }
        .summary div { flex: 1; text-align: center; padding: 10px; }
        .summary .label { font-size: 0.9em; color: #666; }
        .summary .value { font-size: 1.6em; font-weight: bold; color: #2c3e50; margin-top: 5px; }
        .content { padding: 30px; }
        h2 { color: #2c3e50; margin: 25px 0 15px 0; padding-bottom: 8px; border-bottom: 2px solid #3498db; }
        .config-info { background: #d1ecf1; padding: 12px 15px; border-radius: 4px; margin-bottom: 20px; border-left: 3px solid #0c5460; color: #0c5460; font-size: 0.9em; }
        .skipped { background: #fff3cd; padding: 12px 15px; border-radius: 4px; margin-bottom: 20px; border-left: 3px solid #ffc107; }
        .skipped ul { list-style: none; padding-left: 10px; }
        .skipped li { padding: 3px 0; color: #856404; }
        .field-box, .relation-box { margin-bottom: 25px; border: 1px solid #ddd; border-radius: 5px; padding: 20px; background: #fafafa; }
        .field-box h3, .relation-box h3 { color: #2c3e50; font-size: 1.2em; margin-bottom: 10px; }
        .meta { color: #666; margin-bottom: 15px; padding: 8px; background: white; border-radius: 3px; border-left: 3px solid #3498db; }
        .meta strong { color: #3498db; }
        .value-list { display: flex; flex-wrap: wrap; gap: 8px; }
        .value-tag { background: white; padding: 6px 12px; border-radius: 4px; font-size: 0.9em; border: 1px solid #ddd; }
        .more-tag { background: #3498db; color: white; padding: 6px 12px; border-radius: 4px; font-size: 0.9em; }
        .relation-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 15px; }
        .relation-item { border: 1px solid #ddd; border-radius: 4px; padding: 12px; background: white; }
        .parent { font-weight: bold; color: #2c3e50; margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid #ddd; }
        .badge { float: right; background: #3498db; color: white; padding: 2px 8px; border-radius: 10px; font-size: 0.85em; }
        .children { display: flex; flex-wrap: wrap; gap: 6px; }
        .tag { background: #ecf0f1; padding: 4px 8px; border-radius: 3px; font-size: 0.85em; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>📊 字段枚举分析报告</h1>
            <div class="info">${path.basename(sourceFile)} · ${new Date().toLocaleString('zh-CN')}</div>
        </div>
        <div class="summary">
            <div><div class="label">分析行数</div><div class="value">${totalRows.toLocaleString()}</div></div>
            <div><div class="label">总字段</div><div class="value">${columns.length}</div></div>
            <div><div class="label">分析字段</div><div class="value">${analyzableFields.length}</div></div>
            <div><div class="label">发现关系</div><div class="value">${relationships.length}</div></div>
        </div>
        <div class="content">
            <div class="config-info">
                <strong>⚙️ 分析配置:</strong> 
                ${config.分析范围.测试模式 ? `测试模式 (${config.分析范围.测试行数}行)` : '完整分析'} | 
                唯一性阈值: ${(config.字段识别.唯一性阈值 * 100).toFixed(0)}% | 
                最小关系强度: ${config.关系分析.最小关系强度}
            </div>
            ${skippedFields.length > 0 ? `
                <div class="skipped">
                    <strong>⏭️ 跳过的字段:</strong>
                    <ul>${skippedFields.map(f => `<li>• ${f.name} (${f.uniqueCount}个唯一值, ${f.ratio}%)</li>`).join('')}</ul>
                </div>
            ` : ''}
            <h2>🔗 字段关系分析</h2>
            ${relationHtml}
            <h2>📋 字段枚举详情</h2>
            ${fieldTablesHtml}
        </div>
    </div>
</body>
</html>`;

    fs.writeFileSync(outputPath, html, 'utf-8');
}

// 主函数
async function main() {
    console.log('='.repeat(70));
    console.log('📊 可配置的CSV字段枚举分析工具');
    console.log('='.repeat(70));
    
    // 加载配置
    const config = loadConfig();
    
    console.log('\n⚙️  当前配置:');
    console.log(`   测试模式: ${config.分析范围.测试模式 ? '是 (' + config.分析范围.测试行数 + '行)' : '否 (完整分析)'}`);
    console.log(`   唯一性阈值: ${config.字段识别.唯一性阈值 * 100}%`);
    console.log(`   关系分析: ${config.关系分析.启用 ? '启用' : '禁用'}`);
    console.log(`   最小关系强度: ${config.关系分析.最小关系强度}`);
    
    // 确定要分析的文件
    let filesToAnalyze = [];
    if (config.文件选择.分析所有文件) {
        const outputDir = config.输出设置.输出目录;
        const files = fs.readdirSync(outputDir);
        filesToAnalyze = files
            .filter(f => f.endsWith('.csv'))
            .map(f => path.join(outputDir, f));
        console.log(`\n📁 扫描到 ${filesToAnalyze.length} 个CSV文件`);
    } else {
        filesToAnalyze = config.文件选择.指定文件;
        console.log(`\n📁 指定文件: ${filesToAnalyze.length} 个`);
    }
    
    if (filesToAnalyze.length === 0) {
        console.log('❌ 没有找到要分析的文件');
        return;
    }
    
    // 分析每个文件
    for (let i = 0; i < filesToAnalyze.length; i++) {
        const filePath = filesToAnalyze[i];
        const fileName = path.basename(filePath, '.csv');
        
        console.log(`\n${'='.repeat(70)}`);
        console.log(`📄 [${i + 1}/${filesToAnalyze.length}] ${fileName}.csv`);
        console.log('='.repeat(70));
        
        try {
            // 收集统计
            const stats = await collectStats(filePath, config);
            
            // 发现关系
            const relationships = await discoverRelationships(filePath, stats, config);
            
            console.log(`\n   ✅ 发现 ${relationships.length} 个字段关系`);
            
            // 生成报告
            const outputFileName = config.输出设置.报告文件名格式.replace('{文件名}', fileName);
            const outputPath = path.join(config.输出设置.输出目录, outputFileName);
            
            console.log(`\n   📝 生成报告: ${outputFileName}`);
            generateReport(stats, relationships, config, filePath, outputPath);
            
            console.log(`   ✅ 完成!\n`);
            
        } catch (error) {
            console.error(`   ❌ 分析失败:`, error.message);
        }
    }
    
    console.log('='.repeat(70));
    console.log('✅ 所有文件分析完成!');
    console.log('='.repeat(70));
}

main();

